<?php namespace App\Api\Http\ApiControllers;

use App\Application\PayService;
use App\Application\UserService;
use App\Foundation\Service\WechatPayService;
use App\Models\PayLog;
use App\Repositories\Order\OrderRepositoryInterface;
use DB;
use Illuminate\Http\Request;

class PayNotifyController extends Controller
{
    /**
     * @var OrderRepositoryInterface
     */
    protected $order_repository;

    /**
     * @var UserService
     */
    protected $user_service;

    /**
     * @var PayService
     */
    protected $pay_service;

    public function __construct(
        OrderRepositoryInterface $order_repository,
        UserService $user_service,
        PayService $pay_service
    ) {
        $this->order_repository = $order_repository;
        $this->user_service = $user_service;
        $this->pay_service = $pay_service;
    }

    /**
     * 微信公众号支付
     *
     * @param Request $request
     *
     * @return mixed
     */
    public function wechat(Request $request)
    {
        $pay_log = new PayLog();
        $content = strval($request->getContent());
        \Log::info($content);
        if (preg_match('/out_trade_no.*CDATA\[(\w+)\]\]/', $content, $match)) {
            $trade_no = $match[1];
            $pay_log->storeResponse($trade_no, $content);
        }

        $wechat_mp_pay = WechatPayService::wechatMp();
        $response = $wechat_mp_pay->handleNotify(function ($notify, $successful) use ($pay_log) {
            $trade_no = $notify->out_trade_no;

            $end_time = $notify->time_end;
            $end_time = Carbon::parse($end_time)->toDateTimeString();

            return $this->handleNotify($trade_no, $successful, $notify->transaction_id, $end_time, $pay_log);
        });

        return $response;
    }

    /**
     * 测试
     *
     * @param Request $request
     *
     * @return bool
     */
    public function test(Request $request)
    {
        if (!app()->environment('production')) {
            $trade_no = $request->get('trade_no');
            $successful = (bool)$request->get('result', true);
            $out_trade_no = time();
            $end_time = time();
            $pay_log = new PayLog();

            if ($this->handleNotify($trade_no, $successful, $out_trade_no, $end_time, $pay_log)) {
                return 'success';
            }

            return 'failure';
        }

        return response('', 404);
    }

    /**
     * 支付处理
     *
     * @param        $trade_no
     * @param        $successful
     * @param        $out_trade_no
     * @param        $end_time
     * @param PayLog $pay_log
     *
     * @return bool
     */
    private function handleNotify($trade_no, $successful, $out_trade_no, $end_time, PayLog $pay_log)
    {
        if (!$trade_no) {
            return false;
        }
        $order = $this->order_repository->showByTradeNo($trade_no);
        //订单是否存在
        if (!$order) {
            $pay_log->storeNoFound($trade_no, []);

            return true;
        }
        //订单是否已经支付过
        if (!$order->isPending()) {
            $pay_log->storePaid($trade_no);

            return true;
        }
        //支付失败
        if ($successful !== true) {
            $this->pay_service->failure($order, $out_trade_no, $end_time);
            $pay_log->storeFailure($trade_no);

            return true;
        }

        DB::beginTransaction();
        try {
            $end_time = $end_time ?: date('Y-m-d H:i:s');
            //订单支付成功处理
            $this->pay_service->success($order, $out_trade_no, $end_time);
            DB::commit();

            $pay_log->storeResult($trade_no, 'success');

            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            $pay_log->storeException($trade_no, [__FILE__ . ':' . __LINE__ . '==' . $e->getMessage()]);

            \Log::error(__FILE__ . ':' . __LINE__ . ' pay_type=' . $pay_log->pay_type . ';error_msg=' . $e->getMessage());

            return false;
        }

        return false;
    }
}
